<?php


namespace GordenSong\Laravel\Support\Traits;


use GordenSong\Laravel\Exceptions\ValidatorFieldNotExistException;
use GordenSong\Laravel\Utils\RuleUtil;

trait ValidatorTrait
{
	/** @var array */
	protected $attributes = [];
	/** @var array */
	protected $messages = [];
	/** @var array */
	protected $rules = [];

	public function attributes(): array
	{
		return $this->attributes;
	}

	public function rules(): array
	{
		return $this->rules;
	}

	public function messages(): array
	{
		return $this->messages;
	}

	/**
	 * @param array $attributes
	 */
	public function setAttributes(array $attributes): void
	{
		$this->attributes = $attributes;
	}

	/**
	 * @param array $messages
	 */
	public function setMessages(array $messages): void
	{
		$this->messages = $messages;
	}

	/**
	 * overwrite rules
	 * @param array $rules
	 */
	public function setRules(array $rules)
	{
		$this->rules = RuleUtil::normalizeManyRules($rules);
	}

	/**
	 * 定制的规则
	 * @return array
	 */
	public function customizeRules(): array
	{
		return [];
	}

	/**
	 * 要排除的规则
	 * @return array
	 */
	public function excludeRules(): array
	{
		return [];
	}

	/**
	 * @param string $field
	 * @return array
	 * @throws ValidatorFieldNotExistException
	 */
	public function getFieldRules(string $field): array
	{
		if (!$this->hasField($field)) {
			throw new ValidatorFieldNotExistException($field);
		}
		return $this->rules[$field];
	}

	/**
	 * @param string $field
	 * @return bool
	 */
	public function hasField(string $field): bool
	{
		return isset($this->rules[$field]);
	}

	public function addRules(array $rules)
	{
		foreach ($rules as $key => $rule) {
			$this->addRule($key, $rule);
		}

		return $this;
	}

	/**
	 * @param string $key
	 * @param array $rules
	 */
	public function addRule(string $key, array $rules)
	{
		$thisRules = data_get($this->rules, $key, []);

		$this->rules[$key] = array_values(RuleUtil::mergeRules($thisRules, $rules));

		return $this;
	}

	/**
	 * 排除规则
	 *
	 * eg:
	 * 1. <code>except('id', 'title')</code>
	 * 2. <code>except(['title' => ['required'], 'created_at'])</code>
	 *
	 * @param array|string $rules
	 * @return $this
	 */
	public function except($rules)
	{
		$rules = is_string($rules) ? func_get_args() : $rules;

		$this->rules = RuleUtil::diffManyRules($this->rules(), $rules);

		return $this;
	}

	/**
	 * @param string|array $fields
	 * @return $this
	 * @throws ValidatorFieldNotExistException
	 */
	public function only($fields)
	{
		$fields = is_string($fields) ? func_get_args() : $fields;
		if (empty($fields)) {
			return $this;
		}

		$rules = [];
		foreach ($fields as $field) {
			$rule = $this->getFieldRules($field);
			if ($rule) {
				$rules[$field] = $rule;
			}
		}

		$this->rules = RuleUtil::normalizeManyRules($rules);

		return $this;
	}

	/**
	 * @throws ValidatorFieldNotExistException
	 */
	public function hasRule(string $field, string $rule)
	{
		$rules = $this->getFieldRules($field);
		if (empty($rules)) {
			return [];
		}
		return in_array($rule, $rules, true);
	}
}